// SummaryDlg.cpp : implementation file
//

#include "stdafx.h"
#include "LightspeedTraderAPIDemo.h"
#include "SummaryDlg.h"
//#include "afxdialogex.h"

//enum used for API Function Indexing
enum SUMMARY_STATIC { //values that don't change (or at least not very often) for symbols
	SYMBOL,
	COMPANY_NAME,
	EXCHANGE,
	LISTED,
	CLOSE,
	PREV_CLOSE,
	PREV_VOLUME,
	FSI,
	BORROWABLE,
	MARGIN_REQUIREMENT,
	PRIMARY_PREV_CLOSE,
	PRIMARY_MARKET,
	PRIMARY_OPEN,
	PRIMARY_CLOSE,
	SSRI,
	GAP,
	GAP_PERCENT,
	PRIMARY_GAP,
	PRIMARY_GAP_PERCENT,

	END_OF_STATIC_VALUES
};

enum SUMMARY_L1_DYNAMIC { //values that change on L1 updates
	LAST_PRICE = END_OF_STATIC_VALUES,
	OPEN,
	HIGH,
	LOW,
	VOLUME,
	BID,
	ASK,
	BID_SIZE,
	ASK_SIZE,
	LAST_SIZE,
	PRIMARY_LAST,
	PRIMARY_VOLUME,
	PRIMARY_BID,
	PRIMARY_ASK,
	PRIMARY_BID_SIZE,
	PRIMARY_ASK_SIZE,
	LAST_TIME,
	UPDATE_TIME,
	GAP_BID,
	GAP_ASK,
	PRIMARY_GAP_BID,
	PRIMARY_GAP_ASK,

	END_OF_L1_DYNAMIC_VALUES
};

enum SUMMARY_OI_DYNAMIC { //values that change on imbalance updates
	OI_BUY_VOLUME_REG = END_OF_L1_DYNAMIC_VALUES,
	OI_SELL_VOLUME_REG,
	OI_BUY_VOLUME,
	OI_SELL_VOLUME,
	OI_TOTAL_VOLUME,
	OI_REF_PRICE,
	OI_CROSS_TYPE,
	OI_MARKET,
	OI_CLEARING_PRICE,
	OI_NEAR_PRICE,
	OI_FAR_PRICE,
	OI_CONTINUOUS_PRICE,
	OI_CLOSING_ONLY_PRICE,
	OI_TIME,

	END_OF_OI_DYNAMIC_VALUES
};

enum SUMMARY_TF_DYNAMIC { //values that change on TF (chart) updates
	TF_HIGH = END_OF_OI_DYNAMIC_VALUES,
	TF_LOW,
	TF_PREV_CLOSE,
	TF_VOLUME,
	TF_CHANGE,
	TF_PERCENT_CHANGE,
	TF_HIGH_LOW,
	TF_PRICE_RANGE,
	TF_PERCENT_PRICE_RANGE,
	TF_VOLUME_RATE,

	END_OF_TF_DYNAMIC_VALUES
};

// SummaryDlg dialog

IMPLEMENT_DYNAMIC(SummaryDlg, CModelessDialog)

SummaryDlg::SummaryDlg(CWnd* pParent /*=NULL*/)
	: CModelessDialog(SummaryDlg::IDD, pParent)
	, m_SummaryDataListCtrl(CListCtrl())
	, m_SymbolEdit(CEdit())
	, m_TFCombo(CComboBox())
	, summary(0)
	, m_Linked(true)
	, m_TFValue(60)
{
	SetAPIFunctions();
}

SummaryDlg::~SummaryDlg()
{
	//destroy and detach from summary
	if (summary)
	{
		summary->L_Detach(this);
		L_DestroySummary(summary);
	}

	L_DetachFromAppNotifier(this);
}

BOOL SummaryDlg::Create(CWnd *pParentWnd /*= CWnd::FromHandle(L_GetMainWnd())*/)
{
	return __super::Create(SummaryDlg::IDD, pParentWnd);
}

void SummaryDlg::DoDataExchange(CDataExchange* pDX)
{
	__super::DoDataExchange(pDX);

	DDX_Control(pDX,IDC_SUMMARYLIST,m_SummaryDataListCtrl);
	DDX_Control(pDX,IDC_SYMBOLEDIT, m_SymbolEdit);
	DDX_Control(pDX,IDC_TFCOMBO, m_TFCombo);
}

void SummaryDlg::OnOK()
{
	CString sym;
	m_SymbolEdit.GetWindowText(sym);
	if (!sym.IsEmpty())
	{
		if (m_Linked)
		{
			//if linked handle message will take care of entering the new symbol
			L_SetFocusedSymbol(sym.GetBuffer());
		}
		else
		{
			SetSymbol(sym.GetBuffer());
		}

		m_SymbolEdit.SetWindowText("");
	}
}

BOOL SummaryDlg::OnInitDialog()
{
	__super::OnInitDialog();

	DWORD style = m_SummaryDataListCtrl.GetExtendedStyle();
	style |= LVS_EX_FULLROWSELECT;
	style |= LVS_EX_GRIDLINES;
	style |= LVS_EX_DOUBLEBUFFER;
	m_SummaryDataListCtrl.SetExtendedStyle(style);

	m_SummaryDataListCtrl.InsertColumn(0,"API Function", LVCFMT_LEFT, 110, 0);
	m_SummaryDataListCtrl.InsertColumn(1,"Value", LVCFMT_LEFT, 110, 1);

	InitializeDataCtrlRows();

	CString TFString;
	for (int i = 2; i <= 60; ++i)
	{
		TFString.Format("%d",i);
		m_TFCombo.AddString(TFString);
	}
	m_TFCombo.AddString("Day");
	m_TFCombo.SetCurSel(58); //index of the default 60 minutes

	L_AttachToAppNotifier(this);

	return TRUE;
}

void SummaryDlg::SetSymbol(const char *symbol)
{
	if (summary)
	{
		summary->L_Detach(this);
		L_DestroySummary(summary);
	}

	summary = L_CreateSummary(symbol);
	summary->L_Attach(this);

	//If API cached values we won't recieve the initial messages for the symbol
	UpdateStaticValues();
	UpdateL1Values();
	UpdateTFValues();
	UpdateOIValues();
}

void SummaryDlg::SetAPIFunctions()
{
	//clear APIFunction array
	memset(APIFunctions,NULL,sizeof(APIFunctions));

	strcpy_s(APIFunctions[SYMBOL],"Symbol");
	strcpy_s(APIFunctions[COMPANY_NAME], "Company Name");
	strcpy_s(APIFunctions[EXCHANGE], "Exchange");
	strcpy_s(APIFunctions[LISTED], "Listed");
	strcpy_s(APIFunctions[PREV_CLOSE], "Prev Close");
	strcpy_s(APIFunctions[PREV_VOLUME], "Prev Volume");
	strcpy_s(APIFunctions[FSI], "FSI");
	strcpy_s(APIFunctions[BORROWABLE], "Borrowable");
	strcpy_s(APIFunctions[MARGIN_REQUIREMENT], "Margin Requirement");
	strcpy_s(APIFunctions[PRIMARY_PREV_CLOSE], "Primary Prev Close");
	strcpy_s(APIFunctions[PRIMARY_MARKET], "Primary Market");
	strcpy_s(APIFunctions[PRIMARY_OPEN], "Primary Open");
	strcpy_s(APIFunctions[PRIMARY_CLOSE], "Primary Close");
	strcpy_s(APIFunctions[PRIMARY_LAST], "Primary Last");
	strcpy_s(APIFunctions[PRIMARY_VOLUME], "Primary Volume");
	strcpy_s(APIFunctions[PRIMARY_BID], "Primary Bid");
	strcpy_s(APIFunctions[PRIMARY_ASK], "Primary Ask");
	strcpy_s(APIFunctions[PRIMARY_BID_SIZE], "Primary Bid Size");
	strcpy_s(APIFunctions[PRIMARY_ASK_SIZE], "Primary Ask Size");
	strcpy_s(APIFunctions[SSRI], "SSRI");
	strcpy_s(APIFunctions[LAST_PRICE], "Last Price");
	strcpy_s(APIFunctions[OPEN], "Open");
	strcpy_s(APIFunctions[HIGH], "High");
	strcpy_s(APIFunctions[LOW], "Low");
	strcpy_s(APIFunctions[CLOSE], "Close");
	strcpy_s(APIFunctions[VOLUME], "Volume");
	strcpy_s(APIFunctions[BID], "Bid");
	strcpy_s(APIFunctions[ASK], "Ask");
	strcpy_s(APIFunctions[BID_SIZE], "Bid Size");
	strcpy_s(APIFunctions[ASK_SIZE], "Ask Size");
	strcpy_s(APIFunctions[LAST_SIZE], "Last Size");
	strcpy_s(APIFunctions[LAST_TIME], "Last Time");
	strcpy_s(APIFunctions[UPDATE_TIME], "Update Time");
	strcpy_s(APIFunctions[OI_BUY_VOLUME_REG], "OI Buy Volume Reg");
	strcpy_s(APIFunctions[OI_SELL_VOLUME_REG], "OI Sell Volume Reg");
	strcpy_s(APIFunctions[OI_BUY_VOLUME], "OI Buy Volume");
	strcpy_s(APIFunctions[OI_SELL_VOLUME], "OI Sell Volume");
	strcpy_s(APIFunctions[OI_TOTAL_VOLUME], "OI Total Volume");
	strcpy_s(APIFunctions[OI_REF_PRICE], "OI Ref Price");
	strcpy_s(APIFunctions[OI_CROSS_TYPE], "OI Cross Type");
	strcpy_s(APIFunctions[OI_MARKET], "OI Market");
	strcpy_s(APIFunctions[OI_CLEARING_PRICE], "OI Clearing Price");
	strcpy_s(APIFunctions[OI_NEAR_PRICE], "OI Near Price");
	strcpy_s(APIFunctions[OI_FAR_PRICE], "OI Far Price");
	strcpy_s(APIFunctions[OI_CONTINUOUS_PRICE], "OI Coninuous Price");
	strcpy_s(APIFunctions[OI_CLOSING_ONLY_PRICE], "OI Closing Only Price");
	strcpy_s(APIFunctions[OI_TIME], "OI Time");
	strcpy_s(APIFunctions[TF_HIGH], "TF High");
	strcpy_s(APIFunctions[TF_LOW], "TF Low");
	strcpy_s(APIFunctions[TF_PREV_CLOSE], "TF Prev Close");
	strcpy_s(APIFunctions[TF_VOLUME], "TF Volume");
	strcpy_s(APIFunctions[TF_CHANGE], "TF Change");
	strcpy_s(APIFunctions[TF_PERCENT_CHANGE], "TF % Change");
	strcpy_s(APIFunctions[TF_HIGH_LOW], "TF H/L");
	strcpy_s(APIFunctions[TF_PRICE_RANGE], "TF Price Range");
	strcpy_s(APIFunctions[TF_PERCENT_PRICE_RANGE], "TF % Price Range");
	strcpy_s(APIFunctions[TF_VOLUME_RATE], "TF Volume Rate");
	strcpy_s(APIFunctions[GAP], "Gap");
	strcpy_s(APIFunctions[GAP_PERCENT], "Gap Percent");
	strcpy_s(APIFunctions[GAP_BID], "Gap Bid");
	strcpy_s(APIFunctions[GAP_ASK], "Gap Ask");
	strcpy_s(APIFunctions[PRIMARY_GAP], "Primary Gap");
	strcpy_s(APIFunctions[PRIMARY_GAP_PERCENT], "Primary Gap Percent");
	strcpy_s(APIFunctions[PRIMARY_GAP_BID], "Primary Gap Bid");
	strcpy_s(APIFunctions[PRIMARY_GAP_ASK], "Primary Gap Ask");
}

void SummaryDlg::InitializeDataCtrlRows()
{
	for (int i = 0; i < END_OF_TF_DYNAMIC_VALUES; ++i)
	{
		m_SummaryDataListCtrl.InsertItem(i,APIFunctions[i]);
	}
}

void SummaryDlg::UpdateStaticValues()
{
	m_SummaryDataListCtrl.SetRedraw(FALSE); //disable redraw to reduce control flickering
	for (int i = 0; i < END_OF_STATIC_VALUES; ++i)
	{
		m_SummaryDataListCtrl.SetItemText(i, 1, GetTextForFunction(i));
	}
	m_SummaryDataListCtrl.SetRedraw(TRUE);
}

void SummaryDlg::UpdateL1Values()
{
	m_SummaryDataListCtrl.SetRedraw(FALSE); //disable redraw to reduce control flickering
	for (int i = END_OF_STATIC_VALUES; i < END_OF_L1_DYNAMIC_VALUES; ++i)
	{
		m_SummaryDataListCtrl.SetItemText(i, 1, GetTextForFunction(i));
	}
	m_SummaryDataListCtrl.SetRedraw(TRUE);
}

void SummaryDlg::UpdateOIValues()
{
	m_SummaryDataListCtrl.SetRedraw(FALSE); //disable redraw to reduce control flickering
	for (int i = END_OF_L1_DYNAMIC_VALUES; i < END_OF_OI_DYNAMIC_VALUES; ++i)
	{
		m_SummaryDataListCtrl.SetItemText(i, 1, GetTextForFunction(i));
	}
	m_SummaryDataListCtrl.SetRedraw(TRUE);
}

void SummaryDlg::UpdateTFValues()
{
	m_SummaryDataListCtrl.SetRedraw(FALSE); //disable redraw to reduce control flickering
	for (int i = END_OF_OI_DYNAMIC_VALUES; i < END_OF_TF_DYNAMIC_VALUES; ++i)
	{
		m_SummaryDataListCtrl.SetItemText(i, 1, GetTextForFunction(i));
	}
	m_SummaryDataListCtrl.SetRedraw(TRUE);
}

void SummaryDlg::ClearValues()
{
	m_SummaryDataListCtrl.SetRedraw(FALSE);
	for (int i = 0; i < m_SummaryDataListCtrl.GetItemCount(); ++i)
	{
		m_SummaryDataListCtrl.SetItemText(i, 1, "");
	}
	m_SummaryDataListCtrl.SetRedraw(TRUE);
}

//will map index enums to the equivilant API functions
CString SummaryDlg::GetTextForFunction(int function)
{
	CString retString = "";

	switch (function)
	{
	case SYMBOL:
		{
			retString = summary->L_Symbol();
		}
		break;
	case COMPANY_NAME:
		{
			retString = summary->L_CompanyName();
		}
		break;
	case EXCHANGE:
		{
			retString = summary->L_Exchange();
		}
		break;
	case LISTED:
		{
			retString = (summary->L_IsListed()?"Yes":"No");
		}
		break;
	case PREV_CLOSE:
		{
			retString.Format("%.2f", summary->L_PrevClose());
		}
		break;
	case PREV_VOLUME:
		{
			retString.Format("%d", summary->L_PrevVolume());
		}
		break;
	case FSI:
		{
			retString = summary->L_FSI();
		}
		break;
	case BORROWABLE:
		{
			retString.Format("%d", summary->L_Borrowable());
		}
		break;
	case MARGIN_REQUIREMENT:
		{
			retString.Format("%.2f", summary->L_MarginRequirement());
		}
		break;
	case PRIMARY_PREV_CLOSE:
		{
			retString.Format("%.2f", summary->L_PrimaryPrevClose());
		}
		break;
	case PRIMARY_MARKET:
		{
			retString = summary->L_PrimaryMarket();
		}
		break;
	case PRIMARY_OPEN:
		{
			retString.Format("%.2f", summary->L_PrimaryOpen());
		}
		break;
	case PRIMARY_CLOSE:
		{
			retString.Format("%.2f", summary->L_PrimaryClose());
		}
		break;
	case PRIMARY_LAST:
		{
			retString.Format("%.2f", summary->L_PrimaryLast());
		}
		break;
	case PRIMARY_VOLUME:
		{
			retString.Format("%d", summary->L_PrimaryVolume());
		}
		break;
	case PRIMARY_BID:
		{
			retString.Format("%.2f", summary->L_PrimaryBid());
		}
		break;
	case PRIMARY_ASK:
		{
			retString.Format("%.2f", summary->L_PrimaryAsk());
		}
		break;
	case PRIMARY_BID_SIZE:
		{
			retString.Format("%d", summary->L_PrimaryBidSize());
		}
		break;
	case PRIMARY_ASK_SIZE:
		{
			retString.Format("%d", summary->L_PrimaryAskSize());
		}
		break;
	case SSRI:
		{
			retString = summary->L_SSRI();
		}
		break;
	case LAST_PRICE:
		{
			retString.Format("%.2f", summary->L_LastPrice());
		}
		break;
	case OPEN:
		{
			retString.Format("%.2f", summary->L_Open());
		}
		break;
	case HIGH:
		{
			retString.Format("%.2f", summary->L_High());
		}
		break;
	case LOW:
		{
			retString.Format("%.2f", summary->L_Low());
		}
		break;
	case CLOSE:
		{
			retString.Format("%.2f", summary->L_Close());
		}
		break;
	case VOLUME:
		{
			retString.Format("%d", summary->L_Volume());
		}
		break;
	case BID:
		{
			retString.Format("%.2f", summary->L_Bid());
		}
		break;
	case ASK:
		{
			retString.Format("%.2f", summary->L_Ask());
		}
		break;
	case BID_SIZE:
		{
			retString.Format("%d", summary->L_BidSize());
		}
		break;
	case ASK_SIZE:
		{
			retString.Format("%d", summary->L_AskSize());
		}
		break;
	case LAST_SIZE:
		{
			retString.Format("%d", summary->L_LastSize());
		}
		break;
	case LAST_TIME:
		{
			retString.Format("%d", summary->L_LastTime());
		}
		break;
	case UPDATE_TIME:
		{
			retString.Format("%d", summary->L_UpdateTime());
		}
		break;
	case OI_BUY_VOLUME_REG:
		{
			retString.Format("%d", summary->L_OIBuyVolumeReg());
		}
		break;
	case OI_SELL_VOLUME_REG:
		{
			retString.Format("%d", summary->L_OISellVolumeReg());
		}
		break;
	case OI_BUY_VOLUME:
		{
			retString.Format("%d", summary->L_OIBuyVolume());
		}
		break;
	case OI_SELL_VOLUME:
		{
			retString.Format("%d", summary->L_OISellVolume());
		}
		break;
	case OI_TOTAL_VOLUME:
		{
			retString.Format("%d", summary->L_OITotalVolume());
		}
		break;
	case OI_REF_PRICE:
		{
			retString.Format("%.2f", summary->L_OIRefPrice());
		}
		break;
	case OI_CROSS_TYPE:
		{
			retString = summary->L_OICrossType();
		}
		break;
	case OI_MARKET:
		{
			retString = summary->L_OIMarket();
		}
		break;
	case OI_CLEARING_PRICE:
		{
			retString.Format("%.2f", summary->L_OIClearingPrice());
		}
		break;
	case OI_NEAR_PRICE:
		{
			retString.Format("%.2f", summary->L_OINearPrice());
		}
		break;
	case OI_FAR_PRICE:
		{
			retString.Format("%.2f", summary->L_OIFarPrice());
		}
		break;
	case OI_CONTINUOUS_PRICE:
		{
			retString.Format("%.2f", summary->L_OIContinuousPrice());
		}
		break;
	case OI_CLOSING_ONLY_PRICE:
		{
			retString.Format("%.2f", summary->L_OIClosingOnlyPrice());
		}
		break;
	case OI_TIME:
		{
			retString.Format("%d", summary->L_OITime());
		}
		break;
	case TF_HIGH:
		{
			retString.Format("%.2f", summary->L_TFHigh(m_TFValue));
		}
		break;
	case TF_LOW:
		{
			retString.Format("%.2f", summary->L_TFLow(m_TFValue));
		}
		break;
	case TF_PREV_CLOSE:
		{
			retString.Format("%.2f", summary->L_TFPrevClose(m_TFValue));
		}
		break;
	case TF_VOLUME:
		{
			retString.Format("%d", summary->L_TFVolume(m_TFValue));
		}
		break;
	case TF_CHANGE:
		{
			retString.Format("%.2f",summary->L_TFChange(m_TFValue));
		}
		break;
	case TF_PERCENT_CHANGE:
		{
			retString.Format("%.2f%%",summary->L_TFPercentChange(m_TFValue));
		}
		break;
	case TF_HIGH_LOW:
		{
			long hlVal = summary->L_TFHighLow(m_TFValue);
			if (hlVal == -1)
			{
				retString = "L";
			}
			else if (hlVal == 1)
			{
				retString = "H";
			}
		}
		break;
	case TF_PRICE_RANGE:
		{
			retString.Format("%.2f", summary->L_TFPriceRange(m_TFValue));
		}
		break;
	case TF_PERCENT_PRICE_RANGE:
		{
			retString.Format("%.2f%%", summary->L_TFPercentPriceRange(m_TFValue));
		}
		break;
	case TF_VOLUME_RATE:
		{
			retString.Format("%.2f", summary->L_TFVolumeRate(m_TFValue));
		}
		break;
	case GAP:
		{
			retString.Format("%.2f", summary->L_Gap());
		}
		break;
	case GAP_PERCENT:
		{
			retString.Format("%.2f%%", summary->L_GapPercent());
		}
		break;
	case GAP_BID:
		{
			retString.Format("%.2f", summary->L_GapBid());
		}
		break;
	case GAP_ASK:
		{
			retString.Format("%.2f", summary->L_GapAsk());
		}
		break;
	case PRIMARY_GAP:
		{
			retString.Format("%.2f", summary->L_PrimaryGap());
		}
		break;
	case PRIMARY_GAP_PERCENT:
		{
			retString.Format("%.2f%%", summary->L_PrimaryGapPercent());
		}
		break;
	case PRIMARY_GAP_BID:
		{
			retString.Format("%.2f", summary->L_PrimaryGapBid());
		}
		break;
	case PRIMARY_GAP_ASK:
		{
			retString.Format("%.2f", summary->L_PrimaryGapAsk());
		}
		break;
	}

	return retString;
}

//L_Oberver
void SummaryDlg::HandleMessage(L_Message const *pMsg)
{
	switch(pMsg->L_Type())
	{
	case L_MsgSymbolChanged::id:
		{
			if (m_Linked)
			{
				SetSymbol(pMsg->L_Symbol());
			}
		}
		break;
	case L_MsgL1::id:
	case L_MsgL1Change::id:
	case L_MsgIndex::id:
		{
			UpdateStaticValues();
			UpdateL1Values();
		}
		break;
	case L_MsgL1Update::id:
	case L_MsgIndexUpdate::id:
		{
			UpdateL1Values();
		}
		break;
	case L_MsgChartSnapshot::id:
	case L_MsgChartUpdate::id:
		{
			UpdateTFValues();
		}
		break;
	case L_MsgOrderImbalance::id:
		{
			UpdateOIValues();
		}
		break;
	case L_MsgError::id:
		{
			ClearValues();
		}
		break;
	}
}

BEGIN_MESSAGE_MAP(SummaryDlg, CModelessDialog)
	ON_WM_SIZE()
	ON_CBN_SELCHANGE(IDC_TFCOMBO, OnTFChange)
	ON_COMMAND(ID_FILE_LINK ,OnFileLink)
END_MESSAGE_MAP()

// SummaryDlg message handlers

void SummaryDlg::OnTFChange()
{
	CString TFString;
	m_TFCombo.GetLBText(m_TFCombo.GetCurSel(), TFString);

	if (TFString == "Day")
	{
		m_TFValue = -1;
	}
	else
	{
		m_TFValue = atoi(TFString.GetBuffer());
	}

	UpdateTFValues();
}

void SummaryDlg::OnSize(UINT nType, int cx, int cy)
{
	__super::OnSize(nType, cx, cy);

	ResizeControls();
}

void SummaryDlg::ResizeControls()
{
	if (m_hWnd && m_SummaryDataListCtrl.m_hWnd)
	{
		RECT Rect;
		GetClientRect(&Rect);

		RECT ctrlRect;
		m_SummaryDataListCtrl.GetWindowRect(&ctrlRect);
		ScreenToClient(&ctrlRect);

		Rect.top = ctrlRect.top;

		m_SummaryDataListCtrl.MoveWindow(&Rect);
	}
}

void SummaryDlg::OnFileLink()
{
	m_Linked = !m_Linked;

	CMenu *menu = GetMenu();	
	menu->CheckMenuItem(ID_FILE_LINK, (m_Linked ? MF_CHECKED : MF_UNCHECKED) );
	
	if (m_Linked)
	{
		SetSymbol(::L_GetFocusedSymbol());
	}
}